package com.lhczf.lucenedb.service;

import com.lhczf.lucenedb.threads.ConsumerThread;
import com.lhczf.lucenedb.threads.IntegrationIndexThread;
import com.lhczf.lucenedb.threads.MonitorThread;
import com.lhczf.lucenedb.threads.ProducerTread;
import com.lhczf.lucenedb.util.FileUtils;
import com.lhczf.lucenedb.util.LuceneUtil;
import com.lhczf.lucenedb.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class LuceneDbServer {
	
    public static final String INDEX_ROOT_DIR = "system.lucenedb.index.root";
    public static final DateTimeFormatter Y_M_D_DTF = DateTimeFormatter.ofPattern("yyyyMMdd");
    public static final String INDEX_DAYS_DIR = "days";
    public static final String ALL_INDEXS_DIR = "other";
    public static final String INDEX_RECOVER_DIR = "recover";
    public static final String TAXONOMY_DIR_NAME = "taxonomy";
    @Resource
    private DataHub dataHub;
    @Resource
    private LuceneUtil luceneUtil;

    public IndexWriter changeDir(String threadName, String dir) {
        return getIndexWriter(threadName, dir);
    }

    private IndexWriter getIndexWriter(String threadName, String crurentDir) {
        StringBuilder sb = getIndexSb(INDEX_DAYS_DIR, crurentDir);
        File file = new File(sb.toString());
        FileUtils.createDir(file.getAbsolutePath());
        Directory directory = luceneUtil.getDirectory(file);
        IndexWriter indexWriter = luceneUtil.getIndexWriter(directory);

        dataHub.removeDataByKey(threadName);
        dataHub.putMonitorThreadsMap(threadName, indexWriter);
        return indexWriter;
    }

    public void startMonitorThread() {
        ScheduledExecutorService monitorServer = Executors.newSingleThreadScheduledExecutor();
        String monitorPeriod = SpringUtil.getProperValue("system.lucene.thread.monitor.period");
        int period = 60;
        if (SpringUtil.haveLength(monitorPeriod)) {
            period = Integer.valueOf(monitorPeriod);
        }
        log.info("配置的线程监控周期为{}秒", period);
        monitorServer.scheduleAtFixedRate(new MonitorThread(), 60, period, TimeUnit.SECONDS);
    }

    public void startConsumerThread(String indexDir) {
        File dir = new File(indexDir);
        List<File> subDirs = FileUtils.findDirs(dir);
        if (subDirs == null || subDirs.isEmpty()) {
            log.error("当前索引目录下没有文件夹，文件路径结构异常。");
            System.exit(1);
        }
        for (int i = 0; i < subDirs.size(); i++) {
            String consumerThreadName = "lucenedb-thread-consumer-" + (i + 1);
            File subDir = new File(indexDir + File.separator + (i + 1));
            IndexWriter indexWriter = luceneUtil.getIndexWriter(subDir);
            if (indexWriter == null) {
                continue;
            }
            startConsumerThread(consumerThreadName, indexWriter);
            dataHub.putMonitorThreadsMap(consumerThreadName, indexWriter);
        }
    }

    public void startConsumerThread(String consumerThreadName, IndexWriter indexWriter) {
        ConsumerThread consumer = new ConsumerThread(consumerThreadName, indexWriter);
        consumer.start();
    }

    public void startProducerThread(String dataDirs) {
        File dataDir = new File(dataDirs);
        startProducer(dataDir, "lucenedb-thread-producer");
    }

    public void startProducer(File dataDir, String producerThreadName) {
        ProducerTread producer = new ProducerTread(producerThreadName, dataDir);
        producer.start();
        dataHub.putMonitorThreadsMap(producerThreadName, dataDir);
    }

    public void makeWriter() {
        ServerContext serverContext = SpringUtil.getBean(ServerContext.class);
        StringBuilder sb = getTaxoDirStringBuilder();
        DirectoryTaxonomyWriter taxoWriter = luceneUtil.getTaxonmyWriter(sb.toString());
        serverContext.setTaxoWriter(taxoWriter);

        String integrationDir = SpringUtil.getProperValue(INDEX_ROOT_DIR);
        sb = new StringBuilder(integrationDir);
        sb.append(File.separator).append(ALL_INDEXS_DIR).append(File.separator).append("index");

        File integrDir = new File(sb.toString());
        Directory directory = luceneUtil.getDirectory(integrDir);
        IndexWriter indexWriter = luceneUtil.getIndexWriter(directory);
        serverContext.setIntegrWriter(indexWriter);
    }

    public StringBuilder getTaxoDirStringBuilder() {
        return getIndexSb(ALL_INDEXS_DIR, TAXONOMY_DIR_NAME);
    }

    private StringBuilder getIndexSb(String allIndexsDir, String taxonomyDirName) {
        String taxoDir = SpringUtil.getProperValue(INDEX_ROOT_DIR);
        StringBuilder sb = new StringBuilder(taxoDir);
        sb.append(File.separator).append(allIndexsDir).append(File.separator).append(taxonomyDirName);
        return sb;
    }

    public void init() {
        createDir();
        String debug = SpringUtil.getProperValue("system.lucenedb.performance.debug");
        dataHub.setPerformanceDebug(Boolean.valueOf(debug));
    }

    private void createDir() {
        String indexDir = SpringUtil.getProperValue(INDEX_ROOT_DIR);
        FileUtils.createDir(indexDir);
        log.info("当前索引创建后的保存路径: " + indexDir);

        StringBuilder root = new StringBuilder(indexDir);
        root.append(File.separator).append(ALL_INDEXS_DIR).append(File.separator);
        FileUtils.createDir(root.toString() + TAXONOMY_DIR_NAME);
        FileUtils.createDir(root.toString() + "index");

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String todayStr = LocalDateTime.now().format(formatter);
        String tommaryStr = LocalDateTime.now().plusDays(1).format(formatter);

        mkdirs(indexDir, todayStr);
        mkdirs(indexDir, tommaryStr);

        FileUtils.createDir(indexDir + File.separator + INDEX_RECOVER_DIR);

        int available = Runtime.getRuntime().availableProcessors();
        String threads = SpringUtil.getProperValue("system.lucenedb.index.threads");
        if (threads != null && !threads.isEmpty()) {
            int total = Integer.parseInt(threads);
            if (total > available) {
                log.warn("当前创建索引的线程数被重置为" + available + ",因为设置值超过了CPU可用核数");
            } else {
                available = total;
            }
        }
        ServerContext serverContext = SpringUtil.getBean(ServerContext.class);
        serverContext.setThreadTotal(available);
        for (int i = 0; i < available; i++) {
            StringBuilder sb = new StringBuilder(indexDir);
            sb.append(File.separator).append(INDEX_DAYS_DIR).append(File.separator)
                    .append(todayStr).append(File.separator).append(i + 1);
            File dir = new File(sb.toString());
            FileUtils.createDir(dir.getAbsolutePath());
        }

        indexDir = SpringUtil.getProperValue("system.lucenedb.data.root");
        FileUtils.createDir(indexDir);
        log.info("当前数据文件所在的目录: " + indexDir);

        indexDir = SpringUtil.getProperValue("system.lucenedb.index.backup");
        FileUtils.createDir(indexDir);
    }

    private void mkdirs(String indexDir, String tommaryStr) {
        StringBuilder root = new StringBuilder(indexDir);
        root.append(File.separator).append(INDEX_DAYS_DIR)
                .append(File.separator).append(tommaryStr).append(File.separator);
        FileUtils.createDir(root.toString());
    }

    public void startIntegrationIndexThread(String threadName) {
        IntegrationIndexThread integrationIndex = new IntegrationIndexThread(threadName);
        integrationIndex.start();
    }
}
